package com.zw.cloud.global.exception;

import com.zw.cloud.global.response.wrapper.entity.WebResult;
import com.zw.cloud.utils.DingTalkUtils;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.MDC;
import org.springframework.http.HttpStatus;
import org.springframework.http.converter.HttpMessageConversionException;
import org.springframework.validation.BindException;
import org.springframework.web.HttpMediaTypeNotSupportedException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
import org.springframework.web.servlet.NoHandlerFoundException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.Objects;
import java.util.stream.Collectors;

@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {
    private static final String TRACE_ID = "TRACE_ID";

    @ExceptionHandler(value = Exception.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public WebResult<Object> handlerThrowable(Throwable exception, HttpServletRequest request){
        String uri = "";
        if (Objects.nonNull(request)) {
            uri = request.getRequestURI();
            log.error("[GlobalExceptionHandler][handlerThrowable] tid is {},uri is {},error is ",MDC.get(TRACE_ID),request.getRequestURI(),exception);
        } else {
            log.error("[GlobalExceptionHandler][handlerThrowable] tid is {}，error is",MDC.get(TRACE_ID),exception);
        }
        DingTalkUtils.sendDingTalkMsgWithSign("Throwable",MDC.get(TRACE_ID),uri,exception);
        return WebResult.fail(HttpStatus.INTERNAL_SERVER_ERROR.value(),exception.getMessage() == null ?
                "未知异常" : exception.getMessage());
    }

    /*@ExceptionHandler({javax.validation.ValidateException.class})
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public WebResult<Object> validateException(javax.validation.ValidateException e, HttpServletRequest request) {
        log.warn("[GlobalExceptionHandler][validateException] tid is {},uri is {},error is ",MDC.get(TRACE_ID),request.getRequestURI(),e);
        return WebResult.fail(HttpStatus.BAD_REQUEST.value(),MDC.get(TRACE_ID) + ":" + e.getMessage());
    }*/

    @ExceptionHandler({BindException.class, MethodArgumentNotValidException.class})
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public WebResult<Object> bindException(BindException e, HttpServletRequest request) {
        log.warn("[GlobalExceptionHandler][bindException] tid is {},uri is {},error is ",MDC.get(TRACE_ID),request.getRequestURI(),e);
        //String errorMsg = e.getFieldErrors().stream().map((i) -> String.format("%s(%s):%s", i.getField(), i.getRejectedValue(), i.getDefaultMessage())).collect(Collectors.joining(";"));
        String errorMsg = e.getFieldErrors().stream().map((i) -> String.format("%s:%s", i.getField(), i.getDefaultMessage())).collect(Collectors.joining(";"));
        return WebResult.fail(HttpStatus.BAD_REQUEST.value(),MDC.get(TRACE_ID) + ":" + errorMsg);
    }

    @ExceptionHandler({IllegalArgumentException.class})
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public WebResult<Object> illegalArgumentException(IllegalArgumentException e, HttpServletRequest request) {
        log.warn("[GlobalExceptionHandler][illegalArgumentException] tid is {},uri is {},error is ",MDC.get(TRACE_ID),request.getRequestURI(),e);
        return WebResult.fail(HttpStatus.BAD_REQUEST.value(),MDC.get(TRACE_ID) + ":" + e.getMessage());
    }

    @ExceptionHandler({MethodArgumentTypeMismatchException.class})
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public WebResult<Object> methodArgumentTypeMismatchException(MethodArgumentTypeMismatchException e, HttpServletRequest request) {
        log.warn("[GlobalExceptionHandler][methodArgumentTypeMismatchException] tid is {},uri is {},error is ",MDC.get(TRACE_ID),request.getRequestURI(),e);
        return WebResult.fail(HttpStatus.BAD_REQUEST.value(),MDC.get(TRACE_ID) + ":" + e.getMessage());
    }

    @ExceptionHandler({MissingServletRequestParameterException.class})
    @ResponseStatus(HttpStatus.PAYMENT_REQUIRED)
    public WebResult<Object> missingServletRequestParameterException(MissingServletRequestParameterException e, HttpServletRequest request) {
        log.warn("[GlobalExceptionHandler][missingServletRequestParameterException] tid is {},uri is {},error is ",MDC.get(TRACE_ID),request.getRequestURI(),e);
        return WebResult.fail(HttpStatus.PAYMENT_REQUIRED.value(),MDC.get(TRACE_ID) + ":缺少必要参数:" + e.getParameterName());
    }

    @ExceptionHandler({HttpMessageConversionException.class})
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public WebResult<Object> httpMessageConversionException(HttpMessageConversionException e, HttpServletRequest request) {
        log.warn("[GlobalExceptionHandler][httpMessageConversionException],tid is {},uri is {},error is ",request.getRequestURI(),MDC.get(TRACE_ID),e );
        DingTalkUtils.sendDingTalkMsgWithSign("HttpMessageConversionException",MDC.get(TRACE_ID),request.getRequestURI(),e);
        return WebResult.fail(HttpStatus.BAD_REQUEST.value(),e.getMessage());
    }

    @ExceptionHandler({NoHandlerFoundException.class, HttpRequestMethodNotSupportedException.class, HttpMediaTypeNotSupportedException.class})
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public WebResult<Object> servletException(ServletException e, HttpServletRequest request) {
        log.error("[GlobalExceptionHandler][servletException],tid is {},uri is {},error is ",request.getRequestURI(),MDC.get(TRACE_ID),e );
        DingTalkUtils.sendDingTalkMsgWithSign("ServletException",MDC.get(TRACE_ID),request.getRequestURI(),e);
        return WebResult.fail(HttpStatus.BAD_REQUEST.value(),e.getMessage());
    }

    @ExceptionHandler({BizException.class})
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public WebResult<Object> bizException(BizException e, HttpServletRequest request) {
        log.warn("[GlobalExceptionHandler][bizException],tid is {},uri is {},error is ",request.getRequestURI(),MDC.get(TRACE_ID),e );
        return WebResult.fail(HttpStatus.INTERNAL_SERVER_ERROR.value(),e.getMessage());
    }

    @ExceptionHandler({IOException.class})
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public WebResult<Object> ioException(IOException e, HttpServletRequest request) {
        log.error("[GlobalExceptionHandler][ioException],tid is {},uri is {},error is ",request.getRequestURI(),MDC.get(TRACE_ID),e );
        DingTalkUtils.sendDingTalkMsgWithSign("IOException",MDC.get(TRACE_ID),request.getRequestURI(),e);
        return WebResult.fail(HttpStatus.INTERNAL_SERVER_ERROR.value(),e.getMessage());
    }
}
